package com.huayi.datagovernance.utils.io;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileMode;
import cn.hutool.core.lang.Console;
import org.junit.Test;

import java.io.File;
import java.io.RandomAccessFile;
import java.util.List;

/**
 * 文件工具类-FileUtil
 * 在IO操作中，文件的操作相对来说是比较复杂的，但也是使用频率最高的部分，我们几乎所有的项目中几乎都躺着一个叫做FileUtil或者FileUtils的工具类，
 * 我想Hutool应该将这个工具类纳入其中，解决用来解决大部分的文件操作问题。
 *
 * 总体来说，FileUtil类包含以下几类操作工具：
 *
 * 文件操作：包括文件目录的新建、删除、复制、移动、改名等
 * 文件判断：判断文件或目录是否非空，是否为目录，是否为文件等等。
 * 绝对路径：针对ClassPath中的文件转换为绝对路径文件。
 * 文件名：主文件名，扩展名的获取
 * 读操作：包括类似IoUtil中的getReader、readXXX操作
 * 写操作：包括getWriter和writeXXX操作
 * 在FileUtil中，我努力将方法名与Linux相一致，例如创建文件的方法并不是createFile，而是touch，这种统一对于熟悉Linux的人来说，大大提高了上手速度。当然，如果你不熟悉Linux，那FileUtil工具类的使用则是在帮助你学习Linux命令。这些类Linux命令的方法包括：
 *
 * ls 列出目录和文件
 * touch 创建文件，如果父目录不存在也自动创建
 * mkdir 创建目录，会递归创建每层目录
 * del 删除文件或目录（递归删除，不判断是否为空），这个方法相当于Linux的delete命令
 * copy 拷贝文件或目录
 * 这些方法提供了人性化的操作，例如touch方法，在创建文件的情况下会自动创建上层目录（我想对于使用者来说这也是大部分情况下的需求），同样mkdir也会创建父目录。
 *
 * 需要注意的是，del方法会删除目录而不判断其是否为空，这一方面方便了使用，另一方面也可能造成一些预想不到的后果（比如拼写错路径而删除不应该删除的目录），所以请谨慎使用此方法。
 * @author wuch
 * @version 1.0
 * @date 2021/4/21 9:20
 */
public class FileUtilDemo {

    /**
     * 创建
     */
    @Test
    public void test1(){
        //创建File对象
//        newFile(String path) 创建File对象，相当于调用new File()，不做任何处理
//        file(String path) 创建File对象，自动识别相对或绝对路径，相对路径将自动从ClassPath下寻找
        File classFile = FileUtil.file("mapper/master/MasterUserMapper.xml");
//        File classFile = FileUtil.file("D:/IdeaProjects/xjsunyk/src/main/resources/mapper/master/MasterUserMapper.xml");
        System.out.println(classFile.exists());//判断文件是否存在
//        file(String parent, String path) // 此方法会检查slip漏洞
//        file(URI uri) 文件URI
//        file(URL url) 文件URL
//        file(File parent, String path) parent - 父文件对象 path - 文件路径
//        file(File directory, String... names) 父目录，元素名（多层目录名），由外到内依次传入
//        file(String... names) 通过多层目录参数创建文件 此方法会检查slip漏洞，漏洞说明见http://blog.nsfocus.net/zip-slip-2/ 任意文件覆盖漏洞，导致敏感文件被解压覆盖
        File file = FileUtil.file("C:/Users/Administrator","Desktop/0407","createfile.txt");

//        File file = new File("C:/Users/Administrator/Desktop/0407/file.txt");
        /*touch(File file) 文件对象
        创建文件及其父目录，如果这个文件存在，直接返回这个文件
        此方法不对File对象类型做判断，如果File不存在，无法判断其类型*/
        File touch = FileUtil.touch(file);
        /*文件全路径字符串*/
        File touch1 = FileUtil.touch(new File("C:/Users/Administrator/Desktop/0407"),"file1.txt");
        /*父目录，文件路径*/
        File touch2 = FileUtil.touch(new File("C:/Users/Administrator/Desktop/0407"),"file2.txt");
        File touch3 = FileUtil.touch("C:/Users/Administrator/Desktop/0407","file3.txt");

//        FileUtil.createRandomAccessFile(File file, FileMode mode) 创建RandomAccessFile 随机访问 可以从文件任意位置读取内容
        //FileMode 文件读写模式：
//        r：以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
//        rw：打开以便读取和写入。
//        rwd：打开以便读取和写入，相对于 "rw"，"rwd" 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。
//        rws：打开以便读取和写入。相对于 "rw"，"rws" 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。
        RandomAccessFile randomAccessFile = FileUtil.createRandomAccessFile(file, FileMode.rw);

        //创建临时文件 dir - 临时文件创建的所在目录
//        public static File createTempFile(File dir) throws IORuntimeException 创建后的文件名为 prefix[Randon].tmp 默认删除重建
        File tf1 = FileUtil.createTempFile(new File("C:/Users/Administrator/Desktop/0407"));
        Console.log(tf1.getName());//hutool6472993580786745670.tmp
        /*public static File createTempFile(File dir, boolean isReCreat) throws IORuntimeException 创建后的文件名为 prefix[Randon].tmp
        isReCreat - 是否重新创建文件（删掉原来的，创建新的）*/
        File tf2 = FileUtil.createTempFile(new File("C:/Users/Administrator/Desktop/0407"), true);
        Console.log(tf2.getName());//hutool3023122820150814519.tmp
        /*public static File createTempFile(String prefix, String suffix, File dir, boolean isReCreat) throws IORuntimeException
        创建后的文件名为 prefix[Randon].suffix From com.jodd.io.FileUtil prefix - 前缀，至少3个字符 suffix - 后缀，如果null则使用默认.tmp*/
        File tf3 = FileUtil.createTempFile("dalong", ".log", new File("C:/Users/Administrator/Desktop/0407"), true);
        Console.log(tf3.getName());//dalong5931062487798130821.log
    }

    /**
     * 目录的操作
     * 遍历
     */
    @Test
    public void test2(){
        //获取 File 目录
        File dirFile = FileUtil.file("C:/Users/Administrator/Desktop/0407");
        Console.log(FileUtil.isDirectory(dirFile));//判断是否为目录，如果file为null，则返回false
        Console.log(FileUtil.isDirEmpty(dirFile));//目录是否为空
        Console.log(FileUtil.isNotEmpty(dirFile));//目录是否不为空
        Console.log(FileUtil.isSub(FileUtil.file("C:","Users","Administrator","Desktop"),dirFile));//判断给定的目录是否为给定文件或文件夹的子目录

//        listFileNames(String path) 获得指定目录下所有文件 不会扫描子目录
        List<String> fileNames = FileUtil.listFileNames("C:/Users/Administrator/Desktop/0407");
        Console.log(fileNames);
        Console.log("========================");
//      List<File>  loopFiles(String path) 递归遍历目录以及子目录中的所有文件
//      List<File> loopFiles(File file) 递归遍历目录以及子目录中的所有文件
        Console.log("loopFiles:"+FileUtil.loopFiles(dirFile)+":end");

//        loopFiles(File file, FileFilter fileFilter) 递归遍历目录以及子目录中的所有文件 如果提供file为文件，直接返回过滤结果
//        loopFiles(File file, int maxDepth, FileFilter fileFilter) maxDepth 遍历深度 1就一级子目录 ./  2 就是二级子目录  ././
        /*  Console.log(FileUtil.loopFiles(dirFile, new FileFilter(){
            @Override
            public boolean accept(File pathname) {
                return pathname.isFile();
            }
        }));*/
        Console.log(FileUtil.loopFiles(dirFile,2, File::isFile));

//        ls(String path) 列出目录文件 给定的绝对路径不能是压缩包中的路径
        Console.log(FileUtil.ls("C:/Users/Administrator/Desktop/0407"));

    }


}
